package com.zerro.litez.compiler.processor.parser;

import com.zerro.litez.annotations.entity.Link;

import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class TypeParser {

    VariableElement type;
    String entityName;
    String name;
    private static final Map<String, String> typeMap = new HashMap<>();
    private static final List<String> originTypeList = new ArrayList<>();
    private static final List<String> entityTypeList = new ArrayList<>();

    static {
        typeMap.put(String.class.getName(), "text");
        typeMap.put(Integer.class.getName(), "integer");
        typeMap.put(Long.class.getName(), "bigint");
        typeMap.put(Short.class.getName(), "smallint");
        typeMap.put(Byte.class.getName(), "tinyint");
        typeMap.put(boolean.class.getName(), "boolean");
        typeMap.put(Float.class.getName(), "float");
        typeMap.put(Double.class.getName(), "double");

        originTypeList.add(int.class.getName());
        originTypeList.add(long.class.getName());
        originTypeList.add(short.class.getName());
        originTypeList.add(byte.class.getName());
        originTypeList.add(boolean.class.getName());
        originTypeList.add(float.class.getName());
        originTypeList.add(double.class.getName());
    }

    boolean isSimpleType = false;
    String typeStr;
    String sqlType = null;

    String realTypeStr;


    boolean isEnumType = false;
    String[] enumFullName = new String[2];

    boolean isEntityType = false;
    EntityClassParser entityTypeParser = null;
    FieldInfo entityTypePk = null;

    private boolean isArray = false;

    private boolean isContainer = false;
    private String containerType = null;

    public TypeParser(VariableElement type, String entityName) {
        this.type = type;
        this.entityName = entityName;
        this.name = type.getSimpleName().toString();
        typeStr = type.asType().toString();
        realTypeStr = typeStr;
        onParse();
    }

    private void onParse() {

        checkArrayType();
        checkContainerType();

        if (isArray && isContainer) {
            throwExp("数组和容器不能嵌套");
        }

        if (!checkSimpleType()) {
            if (!checkEnumType()) {
                if (!checkEntityType()) {
                    throwExp("不支持的类型" + realTypeStr + "," + typeStr);
                }
            }
        }

    }

    private boolean checkSimpleType() {
        if (typeMap.containsKey(realTypeStr)) {
            sqlType = typeMap.get(realTypeStr);
            isSimpleType = true;
            return true;
        }
        return false;
    }

    private boolean checkEntityType() {
        if (entityTypeList.contains(realTypeStr)) {
            Link link = type.getAnnotation(Link.class);
            if (link == null) {
                throwExp("Entity类型的字段必须加上@Link注解");
            }
            entityTypeParser = EntityClassParser.getParser(realTypeStr);

            String entityTypePkStr = new AnnotationInfo(link).getValue("primaryKey");
            if (entityTypePkStr.isEmpty()) {
                if (entityTypeParser.getPrimaryKeys().isEmpty()) {
                    throwExp("这个Entity类型的字段没有任何主键");
                } else {
                    for (FieldInfo pk : entityTypeParser.getPrimaryKeys()) {
                        if (pk.equals(entityTypeParser.getAutoInc())) {
                            continue;
                        }
                        entityTypePk = pk;
                        break;
                    }
                    if (entityTypePk == null) {
                        entityTypePk = entityTypeParser.getInfoOfField(entityTypePkStr);
                    }
                    if (entityTypePk == null) {
                        throwExp("没有找到可用的主键，" +
                                "请为 <" + entityTypeParser.getEntityFullName() + "> 或其父类设置一个非自增的主键");
                    }

                }
            } else {
                entityTypePk = entityTypeParser.getInfoOfField(entityTypePkStr);
                if (entityTypePk == null) {
                    throwExp("不存在的主键 <" + entityTypePkStr + ">");
                }
            }

            if (entityTypePk.equals(entityTypeParser.getAutoInc())) {
                throwExp("Link Entity时不能将自增列作为Link值,将它的@Link注解的primaryKey值设置为其他的主键列");
            }

            if (entityTypePk.getRealType() == null) {
                throwExp("不支持使用枚举或Entity类型作为Link的主键");
            }
            isEntityType = true;
            return true;
        }

        return false;
    }


    public boolean checkEnumType() {
        TypeElement element = EnumParser.getSupportedEnumMap().get(realTypeStr);
        if (element == null) {
            return false;
        }
        enumFullName[1] = element.getSimpleName().toString();
        String fullName = element.getQualifiedName().toString();
        enumFullName[0] = fullName.substring(0, fullName.length() - enumFullName[1].length() - 1);

        isEnumType = true;
        return true;
    }

    private void checkArrayType() {
        int i = typeStr.indexOf("[]");
        if (i == typeStr.lastIndexOf("[]")) {
            isArray = i > -1;
            if (isArray) {
                realTypeStr = typeStr.substring(0, typeStr.indexOf("[]"));
            }
        } else {
            if (i != -1) {
                throwExp("不能使用复杂数组类型");
            }
        }
    }

    private void checkContainerType() {
        String[] splitType = typeStr.split("<", 2);
        if (splitType.length == 1) {
            isContainer = false;
            return;
        }
        try {
            Class<?> klass = Class.forName(splitType[0]);
            if (!isContainer(klass)) {
                throwExp("使用了未实现 List 或 Set 的容器" + typeStr);
            }
            realTypeStr = splitType[1].substring(0, splitType[1].length() - 1);
            containerType = splitType[0];
            isContainer = true;
        } catch (ClassNotFoundException e) {
            throwExp("使用了不支持或自定义的泛型类，");
        }

    }

    private boolean isContainer(Class<?> klass) {
        for (Class<?> anInterface : klass.getInterfaces()) {
            if (anInterface.equals(Iterable.class)) {
                return true;
            } else {
                if (isContainer(anInterface)) {
                    return true;
                }
            }
        }
        return false;
    }
    
    private void throwExp(String msg) {
        throw new RuntimeException(msg + ",\n位于 <" + entityName + "> 中的 <" + name + ">");
    }


    public String getSqlType() {
        return typeMap.get(type.toString());
    }

    public String[] getEnumFullName() {
        return enumFullName;
    }


    public VariableElement getType() {
        return type;
    }

    public static void addEntityType(TypeElement entity) {
        entityTypeList.add(entity.getQualifiedName().toString());
    }

    public boolean isArray() {
        return isArray;
    }

    public boolean isContainer() {
        return isContainer;
    }


    public String getEntityName() {
        return entityName;
    }

    public String getName() {
        return name;
    }

    public boolean isSimpleType() {
        return isSimpleType;
    }

    public String getTypeStr() {
        return typeStr;
    }

    public boolean isEnumType() {
        return isEnumType;
    }

    public boolean isEntityType() {
        return isEntityType;
    }

    public EntityClassParser getEntityTypeParser() {
        return entityTypeParser;
    }

    public FieldInfo getEntityTypePk() {
        return entityTypePk;
    }

    public String getContainerType() {
        return containerType;
    }
}
